package com.boot.ch4;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;

import lombok.extern.slf4j.Slf4j;

/**
 * @author onlyone
 */
@Configuration
@Slf4j
public class HandlerProcessor implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {

    String                 packageName = "com.boot.ch4.impl";
    private ResourceLoader resourceLoader;
    private Environment    environment;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    // 只扫描外部类
    protected ClassPathScanningCandidateComponentProvider getScanner() {
        return new ClassPathScanningCandidateComponentProvider(false, this.environment) {

            @Override
            protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                boolean isCandidate = false;
                if (beanDefinition.getMetadata().isIndependent()) {
                    if (!beanDefinition.getMetadata().isAnnotation()) {
                        isCandidate = true;
                    }
                }
                return isCandidate;
            }
        };
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        Map<String, Object> orderServiceMap = new HashMap<>();
        ClassPathScanningCandidateComponentProvider scanner = getScanner();
        scanner.setResourceLoader(this.resourceLoader);
        scanner.addIncludeFilter(new AnnotationTypeFilter(HandleType.class));

        // 扫描指定包名下配置类
        Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(packageName);
        for (BeanDefinition candidateComponent : candidateComponents) {
            if (candidateComponent instanceof AnnotatedBeanDefinition) {
                AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
                AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();

                try {
                    Class<?> clazz = Class.forName(annotationMetadata.getClassName(), false,
                                                   Thread.currentThread().getContextClassLoader());
                    HandleType handleType = clazz.getAnnotation(HandleType.class);

                    orderServiceMap.put(handleType.value(), clazz.newInstance());
                } catch (ClassNotFoundException e) {
                    log.error("加载Annotation配置类失败", e);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                }

                // 创建BeanDefinition，创建Bean实例，并注入Spring容器
                BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(HandlerContext.class);
                beanDefinitionBuilder.addConstructorArgValue(orderServiceMap);
                registry.registerBeanDefinition(HandlerContext.class.getSimpleName(),
                                                beanDefinitionBuilder.getBeanDefinition());
            }
        }

    }
}
